/**
 * Copyright (c) 2008, Keisuke Inoue, Syracuse Unviersity
 * All rights reserved.
 *
 */
package edu.syr.iis.web.model;

import java.util.List;
import edu.syr.iis.web.util.HibernateUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

/**
 * Manages database operations for Message table
 * @author kinoue
 *
 */
public class MessageManager
{
	private static Log log = LogFactory.getLog(MessageManager.class);
	
	public List<Message> getMessages(Conversation conversation)
	{
		List<Message> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM Message message " +
					" WHERE message.conversation = :conversation" +
			" ORDER BY message.messageId")
			.setEntity("conversation", conversation)
			.list(); 		
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	/**
	 * Returns list of all Message database records sorted by messageId
	 */
	public List<Message> getMessages(int conversationId)
	{
		return getMessages(conversationId, true);
	}

	/**
	 * Returns list of all Message database records sorted by messageId
	 */
	public List<Message> getMessages(int conversationId, boolean lazy)
	{
		List<Message> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM Message " +
					" WHERE conversation.conversationId = :conversationId" +
			        " ORDER BY sequence")
			        .setInteger("conversationId", conversationId)
					.list(); 
			
			if (!lazy)
			{
				for (Message message: list) 
				{
					message.getDialogueActLabels().size();
					message.getDialogueActs().size();
					message.getConversation().getAnnotators().size();
				}
			}
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	
	
	/**
	 * Returns list of all Message database records sorted by daasetId
	 */
	public List<Message> getMessages()
	{
		List<Message> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM Message ORDER BY MessageId ").list();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}

	public Message getMessage(int messageId)
	{
		return getMessage(messageId, false);
	}

	public Message getMessage(int messageId, boolean lazy)
	{
		Message message = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			Criteria criteria = session.createCriteria(Message.class)
			.add(Restrictions.idEq(messageId));
			
			message = (Message) criteria.uniqueResult();
			
			if (!lazy) 
			{
				message.getDialogueActLabels().size();
				message.getDialogueActs().size();
				message.getConversation().getAnnotators().size();

				Hibernate.initialize(message.getDialogueActLabels());
				Hibernate.initialize(message.getDialogueActs());
				// Hibernate.initialize(message.getSortedDialogueActs());
				Hibernate.initialize(message.getConversation().getAssignments());
				Hibernate.initialize(message.getConversation().getDataset());
				
				// Hibernate.initialize(message.getConversation().getAnnotators());
								
				for (DialogueAct dialogueAct: message.getDialogueActs())
					Hibernate.initialize(dialogueAct.getMatchedDialogueActs());								
			}
			
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return message;
	}
	
	
	public List<Message> getSameMessagesLabeled(Message message)
	{
		List<Message> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM Message message " +
					" WHERE message.content = :content" +
					" AND message != :message" +
					" AND size(message.dialogueActLabels) != 0" +
			" ORDER BY message.messageId")
			.setString("content", message.content)
			.setEntity("message", message)
			.list(); 		
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}



	public List<Message> getSameMessages(Message message)
	{
		List<Message> list = null;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			list = session.createQuery("FROM Message message " +
					" WHERE message.content = :content" +
					" AND message != :message" +
			" ORDER BY message.messageId")
			.setString("content", message.content)
			.setEntity("message", message)
			.list(); 		
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return list;
	}


	public Message getPreviousMessage(Message message)
	{
		Message previous;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		try
		{
			previous = (Message) session.createQuery(
					"FROM Message m1" +
					" WHERE m1.messageId = " +
					" (SELECT max(messageId) FROM Message m2 " +
					" WHERE m2.conversation.dataset = :dataset " +
			" AND m2.messageId < :messageId)")
			.setEntity("dataset", message.conversation.dataset)
			.setInteger("messageId", message.messageId)
			.uniqueResult();

			/*
	    if (previous == null) {
		previous = (Message) session.createQuery(
			"FROM Message m1" +
			" WHERE m1.messageId = " +
			" (SELECT max(messageId) FROM Message m2 " +
			" WHERE m2.conversation.dataset = :dataset " +
		" AND m2.messageId > :messageId)")
		.setEntity("dataset", message.conversation.dataset)
		.setInteger("messageId", message.messageId)
		.uniqueResult();
	    }
			 */
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		return previous;

	}

	public Message getNextMessage(Message message)
	{
		log.debug("Entering with: " + message.getMessageId());
		
		Message next;
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();

		
		try
		{
			next = (Message) session.createQuery(
					"FROM Message m1" +
					" WHERE m1.messageId = " +
					" (SELECT min(messageId) FROM Message m2 " +
					" WHERE m2.conversation.dataset = :dataset " +
			" AND m2.messageId > :messageId)")
			.setEntity("dataset", message.conversation.dataset)
			.setInteger("messageId", message.messageId)
			.uniqueResult();


			if (next == null) {
				next = (Message) session.createQuery(
						"FROM Message m1" +
						" WHERE m1.messageId = " +
						" (SELECT min(messageId) FROM Message m2 " +
						" WHERE m2.conversation.dataset = :dataset " +
				" AND m2.messageId < :messageId)")
				.setEntity("dataset", message.conversation.dataset)
				.setInteger("messageId", message.messageId)
				.uniqueResult();
			}
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
		
		if (next == null)
			log.error("Returning null!");
		return next;
	}

	/**
	 * Updates a Message object.
	 * 
	 * I didn't think I needed this in addition to saveMessage(),
	 * but AnnotateMessageController didn't work it with out.
	 * 
	 */
	public void updateMessage(Message message)
	{
		Session session = HibernateUtil.getSessionFactory()
		.getCurrentSession();
		session.beginTransaction();
		try
		{	    
			session.update(message);
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}


	/**
	 * Saves a Message object.
	 */
	public void saveMessage(Message message)
	{
		Session session = HibernateUtil.getSessionFactory()
		.getCurrentSession();
		session.beginTransaction();
		try
		{
			session.merge(message);
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}

	/**
	 * Deletes Message record with matching messageId 
	 */
	public void deleteMessage(int messageId)
	{
		Session session = 
			HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();	
		try
		{
			session.delete(session.load(Message.class,new Integer(messageId)));         	    			
			session.flush();
			session.getTransaction().commit();
		}
		catch (HibernateException e)
		{
			session.getTransaction().rollback();
			throw e;
		}
	}
}
